package cn.ppool.xmlmapper.router;

import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Map;

public class RequestMappingCreate {
    RequestMappingInfo.BuilderConfiguration config;

    public RequestMappingCreate() {
        this.config = new RequestMappingInfo.BuilderConfiguration();
    }

    private RequestMappingInfo createRequestMappingInfo(String path, RequestMethod[] method) {
        RequestMappingInfo.Builder builder = RequestMappingInfo
                .paths(path)
                .methods(method);
        return builder.options(config).build();
    }

    @Nullable
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        return (requestMapping != null ? fromAnnotationCreateRequestMappingInfo(requestMapping) : null);
    }

    @Nullable
    protected RequestMappingInfo getMappingForMethod(String routerPrefixPath, Method method, Class<?> handlerType) {
        RequestMappingInfo classInfo = createRequestMappingInfo(routerPrefixPath, new RequestMethod[]{RequestMethod.GET});
        RequestMappingInfo methodInfo = createRequestMappingInfo(method);
        if (methodInfo != null) {
            return classInfo.combine(methodInfo);
        } else {
            return classInfo;
        }
    }


    public Map<Method, RequestMappingInfo> detectHandlerMethods(String routerPrefixPath, Class handler) {
        return MethodIntrospector.selectMethods(handler,
                (MethodIntrospector.MetadataLookup<RequestMappingInfo>) method -> {
                    try {
                        return getMappingForMethod(routerPrefixPath, method, handler);
                    } catch (Throwable ex) {
                        throw new IllegalStateException("Invalid mapping on handler class [" + handler.getName() + "]: " + method, ex);
                    }
                });
    }

    private RequestMappingInfo fromAnnotationCreateRequestMappingInfo(RequestMapping requestMapping) {
        RequestMappingInfo.Builder builder = RequestMappingInfo
                .paths(requestMapping.path())
                .methods(requestMapping.method())
                .params(requestMapping.params())
                .headers(requestMapping.headers())
                .consumes(requestMapping.consumes())
                .produces(requestMapping.produces())
                .mappingName(requestMapping.name());
        return builder.options(config).build();
    }


}
